package main;

import parser.*;
import utils.*;

/**
 * This class is used to launch the analyser in console mode.
 * The different switches are set and retrieved here too.
 */

public class Launcher {
	// the switches array contains the different line switches with :
	// switches[i][0] containing the main command switch
	// switches[i][1] containing the alternative command switch
	// switches[i][2] containing the method to be called
	// switches[i][3] containing the help message for this switch
	// /!\ BEWARE /!\ The order the switches are set _IS IMPORTANT_, the first ones will be executed first.
	public static String[][] switches = new String[][]
	{
		{"-h","--help","swHelp","displays this help message"}, // the help switch must be set first (it stops the process) 
		{"-c","--config-file","swConfig","specifies the desired configuration file"}, //the config switch must be set before all other "useful" switches
		{"-d","--dtd-list-file","swDTDList","specifies a file containing a list of dtd addresses to be checked"},
		{"-i", "--input-file", "swInput", "specifies the input file or directory (default is 'dtd')"},
		{"-f","--filters","swFilters","specifies the DTD elements you want to be or not to be checked :\n\t"+
			EDCResource.swCheckAll+" / N"+EDCResource.swCheckAll+" : will check all/none of the below elements\n\t" +
			EDCResource.swCheckAny+" / N"+EDCResource.swCheckAny+" : will check only the ANY elements (+ the ones specified after) / will check all but the Any elements (+ the ones specified after)\n\t" +
			EDCResource.swCheckEmpty+" / N"+EDCResource.swCheckEmpty+" : same as above but with the EMPTY elements\n\t" +
			EDCResource.swCheckRedundancy+" / N"+EDCResource.swCheckRedundancy+" : same as above but for redundant elements\n\t" +
			EDCResource.swCheckStarredChoiceElement+" / N"+EDCResource.swCheckStarredChoiceElement+" : same as above but for the 'Starred Choice Elements' (eg. (a* | b+) or (a* | b+)*, ... )\n\t" +
			EDCResource.swUnStarredChoice+" / N"+EDCResource.swUnStarredChoice+" : same as above but for the 'Unstarred Choices' (eg. (a | b) or (a | b)?, ... )"
		},
		{"-v","--verbose","swVerbose","displays additional information"}
	};
	public static String[] methodArgs;
	public static boolean doParse = true;
	
	/**
	 * Specifies this file or folder as input file or folder
	 * @param input
	 * @throws Exception
	 */
	public static boolean swInput(String input) throws Exception{
		EDCResource.setInput(input);
		return true;
	}
	
	/**
	 * Applies the specified filters
	 * @param filters
	 */
	public static boolean swFilters(String filtersString) {
		EDCResource.setFilters(filtersString);
		return true;
	}
	
	/**
	 * Open the specified configuration file
	 * @param file
	 */
	public static boolean swConfig(String conf) {
		EDCResource.setConfFile(conf);
		return true;
	}
	
	/**
	 * Sets the DTDs to be parsed to those that appear in the specified file
	 * @param file
	 * @throws Exception
	 */
	public static boolean swDTDList(String file) throws Exception {
		EDCResource.setDTDListFile(file);
		return true;
	}
	
	/**
	 * Activates the Verbose option
	 */
	public static boolean swVerbose() {
		EDCResource.setVerbose(true);
		// TODO suppress and regroup every System.out.print from source code
		return true;
	}
	
	/**
	 * Displays the help message
	 */
	public static boolean swHelp(){
		doParse = false;
		for (int i=0; i<switches.length; i++) {
			System.out.println(switches[i][0]+", "+switches[i][1]+"\n\t"+switches[i][3]);
		}
		return false;
	}
	
	public static void lauchMethods() throws Exception {
		String args;
		String methodName;
		Launcher l = new Launcher();
		boolean go = true;
		int i = 0;
		while (i < methodArgs.length && go) {
			if (methodArgs[i] != null) {
				args = methodArgs[i];
				methodName = switches[i][2];
				if (args.length() == 0) {
					java.lang.reflect.Method m = Launcher.class.getMethod(methodName);
					go = ((Boolean)m.invoke(l)).booleanValue();
				} else {
					java.lang.reflect.Method m = Launcher.class.getMethod(methodName,args.getClass());
					go = ((Boolean)m.invoke(l,args)).booleanValue();
				}
			}
			i++;
		}
	}
	
	/**
	 * Sets the method that belongs to the specified command switch
	 * @param switchName
	 * @param args
	 * @throws Exception
	 */
	public static void setMethodArgs(String switchName, String args) throws Exception {
		int i=0;
		boolean found = false;
		while (i<switches.length && !found) {
			found = switches[i][0].equals(switchName) || switches[i][1].equals(switchName);
			if (found) {
				methodArgs[i] = args;
			}
			i++;
		}
		if (!found) {
			throw new Exception("the switch "+switchName+" doesn't exist !");
		}
	}
	
	/**
	 * Retrieves and applies the command switches
	 * @param commandLine
	 * @throws Exception
	 */
	public static void retrieveSwitches(String[] commandLine) throws Exception{
		methodArgs = new String[switches.length];
		
		for (int i=0; i<methodArgs.length; i++) {
			methodArgs[i] = null;
		}
		
		int i=0;
		String args;
		String sw;
		while (i<commandLine.length) {
			if (commandLine[i].startsWith("-")) {
				sw = commandLine[i];
				args="";
				i++;
				while(i<commandLine.length && !commandLine[i].startsWith("-")) {
					args+=commandLine[i]+" ";
					i++;
				}
				args = args.trim();
				
				// set the method arguments for that switch
				setMethodArgs(sw, args);
			} else {
				throw new Exception("Misformed command line");
			}
		}
		
		// launch the methods the switches triggered
		lauchMethods();
	}
	
	/**
	 * Just a test
	 * @param s
	 */
//	public static boolean test(String... s) {
//		System.out.println(s);
//		if (s.length > 0) {
//			for (int i=0; i<s.length; i++)
//				System.out.println(s[i]);
//		}
//		return false;
//
////		Launcher l = new Launcher();
////		String methodName = "test";
////		String arg[] = {"bonjour"};
////		boolean b;
////		try {
////			test(arg);
////			java.lang.reflect.Method m = Launcher.class.getMethod(methodName, arg.getClass());
////			System.out.println(m.getName());
////			System.out.println(m.getReturnType());
////			b = ((Boolean)m.invoke(l,new Object[]{arg})).booleanValue();
////			System.out.println(b);
////		} catch (Exception e) {
////			e.printStackTrace();
////		}
//	}
	
	
	/**
	 * Launches the DTD parser
	 * @param args
	 */
	public static void main(String[] args) {
		Parser parser = new Parser();
		if (args.length == 0) {
			EDCResource.console = true;
			parser.parseDTDs();
		} else {
			try {
				EDCResource.console = true;
				retrieveSwitches(args);
				
				if (doParse) {
					parser.parseDTDs();
				}
			} catch (Exception e) {
				System.out.println(e);
			}
		}
	}
}